package com.theeviljames.pure;

import com.theeviljames.base.IMatrixOps;
import com.theeviljames.base.MatrixOps;
import com.theeviljames.exceptions.MatrixException;

public class ComplexMatrixOps implements IComplexMatrixOps {

	private static IComplexMatrixOps instance = null;
	public static IComplexMatrixOps getComplexMatrixOps(){
		if(instance == null) instance = new ComplexMatrixOps();
		return instance;
	}
	
	public Complex[][] add(Complex[][] a, Complex[][] b) throws MatrixException{
		Complex[][] c = a.clone();
		if(checkDims(a, b)){
			for(int i=0;i<a.length;i++){
				for(int j=0;j<a[i].length;j++){
					c[i][j].add(b[i][j]); 
				}
			}
		}
		else{
			throw new MatrixException("Matrix Dimensions must agree");
		}
		return c;
	}

	public Complex[][] createComplexMatrix(double[][][] values) {
		Complex[][] result = new Complex[values.length][values[0].length];
		for(int i = 0; i < values.length; i++){
			for(int j = 0; j < values[0].length; j++){
				result[i][j] = new Complex(values[i][j][0],values[i][j][1]);
			}
		}
		return result;
	}
	
	public Complex[][] dot(Complex[][] a, Complex[][] b) {
		return times(a,transpose(b));
	}
	public Complex[][] inverse(Complex[][] a) {
		// TODO Auto-generated method stub
		return null;
	}
	public Complex length(Complex[][] a) {
		// TODO Auto-generated method stub
		return null;
	}
	public Complex[][] minus(Complex[][] a, Complex[][] b) {
		Complex[][] c = a.clone();
		if(checkDims(a, b)){
			for(int i=0;i<a.length;i++){
				for(int j=0;j<a[i].length;j++){
					c[i][j] = a[i][j].sub(b[i][j]); 
				}
			}
		}
		return c;
	}
	public Complex[][] scalarTimes(Complex[][] a, Complex b) {
		Complex[][] c = a.clone();
		for(int i = 0 ; i < a.length; i++){
			for(int j = 0; j < a[0].length; j++){
				c[i][j] = a[i][j].mult(b);
			}
		}
		return c;
	}
	public Complex[][] times(Complex[][] a, Complex[][] b) {
		int m = a[0].length;
		int n = a.length;
		
		int p = b[0].length;
		Complex[][] c = new Complex[n][p];
		
		for(int i=0;i<n;i++){
			for(int j=0;j<p;j++){
				Complex val = new Complex(0.0,0.0);
				for(int k=0;k<m;k++){
					val = val.add(a[i][k].mult(b[k][j]));
				}
				c[i][j] = val;
			}
		}
		return c;
	}
	public Complex[][] transpose(Complex[][] a) {
		if(a.length == 0) return a;
		int m = a.length;
		int n = a[0].length;
		Complex[][] b = new Complex[n][m];
		for(int i = 0; i < m; i++){
			for(int j = 0; j < n; j++){
				b[j][i] = a[i][j];
			}
		}
		return b;
	}

	//perhaps use the length of the vector (complex number) to order numbers and split
	//into regions i.e. ++,+-,-+,--
	public Complex[][] sigmoid(Complex[][] a){
		Complex[][] result = new Complex[a.length][a[0].length];
		for(int i = 0; i < a.length; i++){
			for(int j = 0; j < a[0].length; j++){
				result[i][j] = a[i][j].sig1();
			}
		}
		return result;
	}
	
	public Complex[][] deltaSigmoid(Complex[][] a){
		Complex[][] result = new Complex[a.length][a[0].length];
		for(int i = 0; i < a.length; i++){
			for(int j = 0; j < a[0].length; j++){
				result[i][j] = a[i][j].d1();
			}
		}
		return result;
	}

	public boolean checkDims(Complex[][] a, Complex[][] b) {
		// Matrix dims must agree
		if(a.length != 0 && b.length != 0)
			if(a.length == b.length){
				if(a[0].length == b[0].length){
					return true;
				}
			}
 		return false;
	}

	public void print(Complex[][] matrix){
		for(Complex[] row:matrix){
			for(Complex c:row){
				System.out.print(c);
			}
			System.out.println();
		}
		System.out.println();
	}
	
	public static void main(String[] args) {
		IComplexMatrixOps c = getComplexMatrixOps();
		Complex a = new Complex(1,1);
		Complex b = new Complex(2,2);
		Complex c1 = new Complex(3,3);
		Complex d = new Complex(4,4);
		Complex[][] weights = new Complex[][]{{a,b},{c1,d}};
		Complex[][] inputs = new Complex[][]{{b,a},{d,c1}};
		Complex[][] result = c.minus(weights, inputs);
		c.print(result);
		
	}
}

